import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:website.core/core/application/blocs/app_navigator_bloc/bloc.dart';
import 'package:website.core/core/application/blocs/app_navigator_bloc/models/page_models/account_page_model.dart';
import 'package:website.core/core/application/blocs/app_navigator_bloc/models/page_models/home_page_model.dart';
import 'package:website.core/core/application/blocs/app_navigator_bloc/models/page_models/web_purchase_item_page_model.dart';
import 'package:website.core/core/application/blocs/auth_bloc/bloc.dart';
import 'package:website.core/core/domain/entities/user.dart';
import 'package:website.core/core/domain/use_cases/sign_out/use_case.dart';

part 'bloc_state.dart';

class AccountPageBloc extends Cubit<AccountPageBlocState> {
  AccountPageBloc({
    required AccountPageModel pageModel,
    required AppNavigatorBloc appNavigatorBloc,
    required AuthBloc authBloc,
    required SignOut signOut,
  })  : _pageModel = pageModel,
        _appNavigatorBloc = appNavigatorBloc,
        _authBloc = authBloc,
        _signOut = signOut,
        super(_getInitialState(
          authBlocState: authBloc.state as AuthorizedAuthBlocState,
        )) {
    _authBlocSubscription = authBloc.stream.listen((authBlocState) {
      _onAuthBlocStateChanged(authBlocState as InitializedAuthBlocState);
    });
  }

  AccountPageModel _pageModel;

  final AppNavigatorBloc _appNavigatorBloc;
  final AuthBloc _authBloc;

  final SignOut _signOut;

  late final StreamSubscription<AuthBlocState> _authBlocSubscription;

  set pageModel(AccountPageModel pageModel) {
    _pageModel = pageModel;
  }

  static AccountPageBlocState _getInitialState({
    required AuthorizedAuthBlocState authBlocState,
  }) {
    return AccountPageBlocState(
      user: authBlocState.user,
    );
  }

  void openHomePage() {
    final pageModel = HomePageModel();

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void openWebPurchaseItemPage() {
    final pageModel = WebPurchaseItemPageModel();

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void openAccountPage() {
    final pageModel = AccountPageModel(
      fragmentModel: const AccountOverviewAccountPageFragmentModel(),
    );

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void requestSigningOut() {
    final authBlocState = _authBloc.state;

    if (authBlocState is! AuthorizedAuthBlocState) {
      return;
    }

    final refreshToken = authBlocState.accessCredentials.refreshToken;

    unawaited(_signOut(
      refreshToken: refreshToken,
    ));

    final pageModel = HomePageModel();

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );

    _authBloc.setAuthenticationData(
      accessCredentials: () => null,
      user: () => null,
    );
  }

  void openOverviewFragment() {
    const fragmentModel = AccountOverviewAccountPageFragmentModel();

    final pageModel = _pageModel.copyWith(
      fragmentModel: () => fragmentModel,
    );

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void openTransactionHistoryFragment() {
    const fragmentModel = TransactionHistoryAccountPageFragmentModel();

    final pageModel = _pageModel.copyWith(
      fragmentModel: () => fragmentModel,
    );

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void openPurchaseManagementFragment() {
    const fragmentModel = PurchaseManagementAccountPageFragmentModel();

    final pageModel = _pageModel.copyWith(
      fragmentModel: () => fragmentModel,
    );

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void openPaymentMethodFragment() {
    const fragmentModel = PaymentMethodAccountPageFragmentModel();

    final pageModel = _pageModel.copyWith(
      fragmentModel: () => fragmentModel,
    );

    _appNavigatorBloc.pushPageReplacement(
      pageModel: pageModel,
    );
  }

  void _onAuthBlocStateChanged(InitializedAuthBlocState authBlocState) {
    if (authBlocState is! AuthorizedAuthBlocState) {
      return;
    }

    emit(state.copyWith(
      user: () => authBlocState.user,
    ));
  }

  @override
  Future<void> close() {
    _authBlocSubscription.cancel();
    return super.close();
  }
}
